package Metadata;

import Common.*;


import heap.Heapfile;
import heap.RID;
import heap.Scan;
import heap.Tuple;
import index.BTFile;
import index.BTFileScan;
import index.FloatKey;
import index.IntegerKey;
import index.KeyClass;
import index.StringKey;

import java.util.*;

import Transaction.Transaction;

public class HeapfileInterface implements GlobalConst {

	public static void insertRec(String relation, int attrCnt,
			attrNode[] attrList, Transaction tx) throws Exception {

		tableSchema relRec = new tableSchema();
		int attrCount = 0;
		int indexCount = 0;
		int count = 0;
		int intVal = 0;
		float floatVal = (float) 0.0;
		String strVal = null;
		RID rid = null;

		// DELETE FOLLOWING ON RETURN
		attrSchema[] attrRecs = null;
		Tuple tuple = null;
		IndexSchema[] indexRecs = null;
		BTFile btree = null;

		Heapfile heap = null;

		// GET RELATION
		// System.out.println("relation:"+relation);
		GoggleDB.tableMgr.getInfo(relation, relRec, tx);
		// relRec = Global.TableMgr.tableInfo.get(relation);
		// CHECK FOR VALID NO OF RECORDS

		if (relRec.attrCnt != attrCnt) {

		}

		Types[] typeArray = new Types[attrCnt];
		short[] sizeArray = new short[attrCnt];
		for (int i = 0; i < attrCnt; i++)
			typeArray[i] = new Types();
		// GET INFO ON ATTRIBUTES

//		Global.timer.start("insert");
		attrRecs = GoggleDB.attrMgr.getTableInfo(relation, tx);
		// attrRecs = Global.TableMgr.relInfo.get(relation);
		attrCount = attrRecs.length;
//		Global.timer.end("insert");

		// CHECK ATTRIBUTE LIST

		for (int z = 0; z < attrCnt; z++) {
			if (attrRecs[z].attrName.equalsIgnoreCase(attrList[z].attrName) == true) {
				
			}
		}
		indexRecs = GoggleDB.indexMgr.getRelInfo(relation, indexCount, tx);
		if (indexRecs != null)
			indexCount = indexRecs.length;

		tuple = new Tuple(Tuple.maxSize);

		count = GoggleDB.attrMgr.getTupleStructure(relation, count, typeArray,
				sizeArray, tx);

		tuple.setHdr((short) count, typeArray, sizeArray);

		// CONVERT DATA STRINGS TO VARIABLE VALUES & INSERT INTO TUPLE

		for (int i = 0; i < relRec.attrCnt; i++) {

			switch (attrRecs[i].attrType.attrType) {

			case Types.BOOLEAN:
				;
			case (Types.INT):

				// System.out.println("attrList:"+attrRecs[i].attrType.attrType);
				Integer integerVal = new Integer(attrList[i].attrValue);
				intVal = integerVal.intValue();
				tuple.SsetIntFld(attrRecs[i].attrPos, intVal);
				break;

			case (Types.FLOAT):
				Float floatVal1 = new Float(attrList[i].attrValue);
				float fVal = floatVal1.floatValue();
				// System.out.println("fval:"+fVal);
				tuple.SsetFloFld(attrRecs[i].attrPos, fVal);
				// System.out.println(tuple.getFloFld(attrRecs[i].attrPos,tx,relation));
				break;
			case Types.VARCHAR:
				;
			case Types.DATETIME:
				;
			case Types.TIMESTAMP:
				;
			case Types.DECIMAL:
				;
			case (Types.CHAR): {
				// System.out.println("attr:"+attrList[i].attrValue+"
				// "+attrRecs[i].attrPos);
				tuple.SsetStrFld(attrRecs[i].attrPos, attrList[i].attrValue);
				// System.out.println("haha"+attrList[i].attrValue);
				break;
			}

			default:
				System.out.println("Error in insertRec");
			}
		}

		// System.out.println("shfjsdkjfks:"+tuple.getStrFld(1));

		// GET DATAFILE

		heap = new Heapfile(relation, tx);

		// INSERT INTO DATAFILE
//		Global.timer.start("insRec");
		rid = heap.insertRecord(tuple.getTupleByteArray(tx), tx, relation);
//		Global.timer.end("insRec");

		// NOW INSERT INTO EACH INDEX FOR RELATION
		Types attrType = new Types(Types.INT);
		int attrPos = 0;
		int attrLen;
		KeyClass key = null;
		for (int i = 0; i < relRec.indexCnt; i++) {
			// FIND INDEXED ATTRIBUTE

			for (int x = 0; x < attrCnt; x++) {
				if (attrRecs[x].attrName
						.equalsIgnoreCase(indexRecs[i].attrName) == true) {
					attrType = attrRecs[x].attrType;
					attrPos = attrRecs[x].attrPos;
					break;
				}
			}

			// PULL OUT KEY

			switch (attrType.attrType) {
			case Types.BOOLEAN:
				;
			case Types.INT:
				intVal = tuple.getIntFld(attrPos, tx, relation);
				IntegerKey k1 = new IntegerKey(intVal);
				key = k1;
				break;

			case Types.FLOAT:
				floatVal = tuple.getFloFld(attrPos, tx, relation);
				FloatKey k2 = new FloatKey(new Float(floatVal)); // no
				// FloatKey
				key = k2;
				// System.out.println("haha"+floatVal);
				break;
			case Types.VARCHAR:
				;
			case Types.DATETIME:
				;
			case Types.TIMESTAMP:
				;
			case Types.DECIMAL:
				;
			case Types.CHAR:
				strVal = tuple.getStrFld(attrPos, tx, relation);
				StringKey k3 = new StringKey(strVal);

				key = k3;
				break;
			default:
				System.out.println("Error in insertRecUT");
			}

			// INSERT INTO INDEX

			// BTREE INSERT CODE

			if (indexRecs[i].accessType.indexType == IndexType.B_Index) {
				btree = new BTFile(indexRecs[i].IndexName);
				btree.insert(key, rid, tx, indexRecs[i].IndexName);
			}

		}

	}

	public void CreatExitTable(String oldtable, String relation, Transaction tx)
			throws Exception {
		GoggleDB.tableMgr.CreatExitTable(oldtable, relation, tx);
	}

	public static void deleteRec(String tableName, RID record, Transaction tx)
			throws Exception {
		Heapfile heap = new Heapfile(tableName, tx);
		// System.out.println("hehe"+tableName);
		tableSchema relRec = new tableSchema();
		GoggleDB.tableMgr.getInfo(tableName, relRec, tx);
		int attrCnt = relRec.attrCnt;

		IndexSchema[] indexRecs = GoggleDB.indexMgr.getRelInfo(tableName, 0, tx);

		Types attrType = new Types(Types.INT);
		// System.out.println(tableName);
		attrSchema[] attrRecs = GoggleDB.attrMgr.getTableInfo(tableName, tx);
		// attrSchema[] attrRecs = GoggleDB.tableMgr.relInfo.get(tableName);
		int attrPos = 0;
		Types[] typeArray = new Types[attrCnt];
		short[] sizeArray = new short[attrCnt];
		for (int i = 0; i < attrCnt; i++)
			typeArray[i] = new Types();
		Tuple tuple = heap.getRecord(record, tx, tableName);
		int count = 0;
		count = GoggleDB.attrMgr.getTupleStructure(tableName, count, typeArray,
				sizeArray, tx);

		tuple.setHdr((short) count, typeArray, sizeArray);
		int intVal = 0;
		float floatVal = (float) 0.0;
		String strVal = null;
		KeyClass key = null;
		BTFile btree = null;
		for (int i = 0; i < relRec.indexCnt; i++) {

			for (int x = 0; x < attrCnt; x++) {
				if (attrRecs[x].attrName
						.equalsIgnoreCase(indexRecs[i].attrName) == true) {
					attrType = attrRecs[x].attrType;
					attrPos = attrRecs[x].attrPos;
					break;
				}
			}

			// PULL OUT KEY

			switch (attrType.attrType) {
			case Types.BOOLEAN:
				;
			case Types.INT:
				intVal = tuple.getIntFld(attrPos, tx, tableName);
				IntegerKey k1 = new IntegerKey(intVal);
				key = k1;
				break;

			case Types.FLOAT:
				floatVal = tuple.getFloFld(attrPos, tx, tableName);
				FloatKey k2 = new FloatKey((int) floatVal); // no
				// FloatKey
				key = k2;
				break;
			case Types.VARCHAR:
				;
			case Types.DATETIME:
				;
			case Types.TIMESTAMP:
				;
			case Types.DECIMAL:
				;
			case Types.CHAR:
				strVal = tuple.getStrFld(attrPos, tx, tableName);
				StringKey k3 = new StringKey(strVal);
				key = k3;
				break;
			default:
				System.out.println("Error in insertRecUT");
			}

			// INSERT INTO INDEX

			// BTREE INSERT CODE

			if (indexRecs[i].accessType.indexType == IndexType.B_Index) {
				btree = new BTFile(indexRecs[i].IndexName);
				btree.Delete(key, record, tx, indexRecs[i].IndexName);
			}

		}

		heap.deleteRecord(record, tx, tableName);

	}
	
	public static void updateRec(RID rid,String relation, int attrCnt,
			attrNode[] attrList, Transaction tx) throws Exception {

		tableSchema relRec = new tableSchema();
		int attrCount = 0;
		int indexCount = 0;
		int count = 0;
		int intVal = 0;
		float floatVal = (float) 0.0;
		String strVal = null;
		

		// DELETE FOLLOWING ON RETURN
		attrSchema[] attrRecs = null;
		Tuple tuple = null;
		IndexSchema[] indexRecs = null;
		BTFile btree = null;

		Heapfile heap = null;

		// GET RELATION
		// System.out.println("relation:"+relation);
		GoggleDB.tableMgr.getInfo(relation, relRec, tx);
		// relRec = GoggleDB.tableMgr.tableInfo.get(relation);
		// CHECK FOR VALID NO OF RECORDS

		if (relRec.attrCnt != attrCnt) {

		}

		Types[] typeArray = new Types[attrCnt];
		short[] sizeArray = new short[attrCnt];
		for (int i = 0; i < attrCnt; i++)
			typeArray[i] = new Types();
		// GET INFO ON ATTRIBUTES

//		Global.timer.start("insert");
		attrRecs = GoggleDB.attrMgr.getTableInfo(relation, tx);
		// attrRecs = GoggleDB.tableMgr.relInfo.get(relation);
		attrCount = attrRecs.length;
//		Global.timer.end("insert");

		// CHECK ATTRIBUTE LIST

		for (int z = 0; z < attrCnt; z++) {
			if (attrRecs[z].attrName.equalsIgnoreCase(attrList[z].attrName) == true) {

			}
		}
		indexRecs = GoggleDB.indexMgr.getRelInfo(relation, indexCount, tx);
		if (indexRecs != null)
			indexCount = indexRecs.length;

		tuple = new Tuple(Tuple.maxSize);

		count = GoggleDB.attrMgr.getTupleStructure(relation, count, typeArray,
				sizeArray, tx);

		tuple.setHdr((short) count, typeArray, sizeArray);

		// CONVERT DATA STRINGS TO VARIABLE VALUES & INSERT INTO TUPLE

		for (int i = 0; i < relRec.attrCnt; i++) {

			switch (attrRecs[i].attrType.attrType) {

			case Types.BOOLEAN:
				;
			case (Types.INT):

				// System.out.println("attrList:"+attrRecs[i].attrType.attrType);
				Integer integerVal = new Integer(attrList[i].attrValue);
				intVal = integerVal.intValue();
				tuple.SsetIntFld(attrRecs[i].attrPos, intVal);
				break;

			case (Types.FLOAT):
				Float floatVal1 = new Float(attrList[i].attrValue);
				float fVal = floatVal1.floatValue();
				// System.out.println("fval:"+fVal);
				tuple.SsetFloFld(attrRecs[i].attrPos, fVal);
				// System.out.println(tuple.getFloFld(attrRecs[i].attrPos,tx,relation));
				break;
			case Types.VARCHAR:
				;
			case Types.DATETIME:
				;
			case Types.TIMESTAMP:
				;
			case Types.DECIMAL:
				;
			case (Types.CHAR): {
				// System.out.println("attr:"+attrList[i].attrValue+"
				// "+attrRecs[i].attrPos);
				tuple.SsetStrFld(attrRecs[i].attrPos, attrList[i].attrValue);
				// System.out.println("haha"+attrList[i].attrValue);
				break;
			}

			default:
				System.out.println("Error in insertRec");
			}
		}

		// System.out.println("shfjsdkjfks:"+tuple.getStrFld(1));

		// GET DATAFILE

		heap = new Heapfile(relation, tx);

		// INSERT INTO DATAFILE
//		Global.timer.start("insRec");
		heap.updateRecord(rid,tuple, tx, relation);
//		Global.timer.end("insRec");

		// NOW INSERT INTO EACH INDEX FOR RELATION
		Types attrType = new Types(Types.INT);
		int attrPos = 0;
		int attrLen;
		KeyClass key = null;
		for (int i = 0; i < relRec.indexCnt; i++) {
			// FIND INDEXED ATTRIBUTE

			for (int x = 0; x < attrCnt; x++) {
				if (attrRecs[x].attrName
						.equalsIgnoreCase(indexRecs[i].attrName) == true) {
					attrType = attrRecs[x].attrType;
					attrPos = attrRecs[x].attrPos;
					break;
				}
			}

			// PULL OUT KEY

			switch (attrType.attrType) {
			case Types.BOOLEAN:
				;
			case Types.INT:
				intVal = tuple.getIntFld(attrPos, tx, relation);
				IntegerKey k1 = new IntegerKey(intVal);
				key = k1;
				break;

			case Types.FLOAT:
				floatVal = tuple.getFloFld(attrPos, tx, relation);
				FloatKey k2 = new FloatKey(new Float(floatVal)); // no
				// FloatKey
				key = k2;
				// System.out.println("haha"+floatVal);
				break;
			case Types.VARCHAR:
				;
			case Types.DATETIME:
				;
			case Types.TIMESTAMP:
				;
			case Types.DECIMAL:
				;
			case Types.CHAR:
				strVal = tuple.getStrFld(attrPos, tx, relation);
				StringKey k3 = new StringKey(strVal);

				key = k3;
				break;
			default:
				System.out.println("Error in insertRecUT");
			}

			// INSERT INTO INDEX

			// BTREE INSERT CODE

			if (indexRecs[i].accessType.indexType == IndexType.B_Index) {
				btree = new BTFile(indexRecs[i].IndexName);
				btree.insert(key, rid, tx, indexRecs[i].IndexName);
			}

		}

	}

	public static void createIndex(String tableName, String attrName,
			String indexName, IndexType accessType, Transaction tx)
			throws Exception {
		// System.out.println("haha:"+"table"+" "+tableName+" "+indexName);
		GoggleDB.tableMgr.addIndex(tableName, attrName, indexName, accessType, tx);
	}

	public static void dropIndex(String tableName, String indexName,
			IndexType accessType, Transaction tx) throws Exception {
		GoggleDB.tableMgr.dropIndex(tableName, indexName, accessType, tx);
	}

	public static void dropTable(String tableName, Transaction tx)
			throws Exception {
		GoggleDB.tableMgr.destroyRel(tableName, tx);
	}
	public static void dropTempTable(Transaction tx) throws Exception
	{
		GoggleDB.tableMgr.destroyTemoRel(tx);
	}

	public static attrSchema[] getTableInfo(String tableName, Transaction tx)
			throws Exception {
		// System.out.println("table:"+tableName);
		return GoggleDB.attrMgr.getTableInfo(tableName, tx);
		// return GoggleDB.tableMgr.relInfo.get(tableName);
	}

	

	public static void createTable(String tableName, int attrCnt,
			attrInfo[] attrList, Transaction tx) throws Exception {
		GoggleDB.tableMgr.createRel(tableName, attrCnt, attrList, tx);
	}

	public static Scan getTableIterator(String relation, Transaction tx)
			throws Exception {
		// System.out.println("relation:"+relation);
		return new Scan(new Heapfile(relation, tx), tx);
	}

	public static int deleteAll(String tableName, Transaction tx)
			throws Exception {
		// System.out.println("tableName:"+tableName);
		Scan pscan = getTableIterator(tableName, tx);

		RID rid = new RID();
		int i = 0;
		while (true) {
			i++;
			Tuple tuple = null;
			tuple = pscan.getNext(rid, tx, tableName);

			if (tuple == null) {
				// System.out.println("sdjfks");
				return i;
			}
			// System.out.println(tuple.toString()+" "+rid.slotNo+"
			// "+rid.pageNo.pageId+" "+i);
			deleteRec(tableName, rid, tx);
		}

	}

	public static void getTupleStructure(Tuple tuple, String relation,
			int attrCnt, Transaction tx) throws Exception {
		Types[] typeArray = new Types[attrCnt];
		short[] sizeArray = new short[attrCnt];
		// System.out.println(attrCnt);
		for (int i = 0; i < attrCnt; i++)
			typeArray[i] = new Types();
		int count = GoggleDB.attrMgr.getTupleStructure(relation, attrCnt,
				typeArray, sizeArray, tx);

		tuple.setHdr((short) count, typeArray, sizeArray);
	}

	public static BTFileScan getBTreeIterator(String relname, String attrName,
			Transaction tx, KeyClass lo_key, KeyClass hi_key) throws Exception {
		IndexSchema attr = new IndexSchema();
		
		if (GoggleDB.indexMgr.getaInfo(relname,attrName, attr, tx)) {
			BTFile btree = new BTFile(attr.IndexName);
			return btree.newScan(lo_key, hi_key, tx);
		} else {
			return null;
		}
	}
	
	public static boolean hasIndex (String relname, String attrName,
			Transaction tx )throws Exception {
		IndexSchema attr = new IndexSchema();
		GoggleDB.attrMgr.getTableInfo(relname, tx);
		return GoggleDB.indexMgr.getaInfo(relname,attrName, attr, tx);
	}

	public static Tuple getTuple(RID rid, Transaction tx, String table)
			throws Exception {
		return new Heapfile(table, tx).getRecord(rid, tx, table);
	}

	public static boolean createDB(Transaction tx,String DBName) throws Exception {
		//if (GoggleDB.storageInterface.add_db(tx, DBName).pageId == 0)
		  if (GoggleDB.storageInterface.get_tables_by_db(DBName).size()==0)
		{
			return false;
		} else {
			return true;
		}
	}

	public static void dropDB(String DBName, Transaction tx) throws Exception {
		ArrayList<String> tables = GoggleDB.storageInterface.get_tables_by_db(DBName
				+ ".");
		for (int i = 0; i < tables.size(); i++) {
			String table = tables.get(i);
			dropTable(table, tx);
		}
	}



	/**
	 * @param string
	 * @param tx
	 */
	public static void dropView(String string, Transaction tx) {
		// TODO Auto-generated method stub
		
	}
}
